﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace robotGUI
{
    public partial class frmSpeedCal : Form
    {
        bool resTestCompleted;
        bool speedTestCompleted;
        long currentImpulses;
        long impulseOffset;
        float pulsesPerMeter;
        bool speedTestEnabled;
        float currentSpeed;
        int filterRatio = 10;
        float topSpeed;

        public frmSpeedCal()
        {
            InitializeComponent();
        }

        Command[] CommandsOfInterest = new Command[] { Command.CALIBRATION_DONE, Command.PULSES_PER_METER, Command.MAX_SPEED_PPS };
        frmMain.NewMessageEventHandler newMessage;
        robotSettings.ParameterArrivedEventHandler parameterArrived;
        robotSettings.StatusEventHandler statusEvent;

        private void frmSpeedCal_Load(object sender, EventArgs e)
        {
            newMessage = new frmMain.NewMessageEventHandler(frmSpeedCal_NewMsg);
            parameterArrived = new robotSettings.ParameterArrivedEventHandler(Settings_ParameterArrived);
            statusEvent = new robotSettings.StatusEventHandler(Settings_StatusEvent);
            ((frmMain)Owner).NewMessage += newMessage;
            ((frmMain)Owner).Settings.StatusEvent += statusEvent;
            ((frmMain)Owner).Settings.ParameterArrived += parameterArrived;
            ((frmMain)Owner).Settings.getValue(CommandsOfInterest);
            numMeters.Value = (decimal)Properties.Settings.Default.courseLength;
            resTestCompleted = false;
            speedTestCompleted = false;
            currentImpulses = 0;
            impulseOffset = 0;
            pulsesPerMeter = 0;
            currentSpeed = 0;
            speedTestEnabled = false;
            topSpeed = 0;
        }

        void Settings_StatusEvent(object sender, robotSettings.StatusEventArgs e)
        {
            lblStatus.Text = e.Message;
        }

        void Settings_ParameterArrived(object sender, robotSettings.ParameterEventArgs e)
        {
            if (e.command == Command.CALIBRATION_DONE)
            {
                if (((frmMain)Owner).Settings.CALIBRATION_DONE.CAL_ENCODER)
                {
                    label1.Text = "Encoder Resolution (Done)";
                    resTestCompleted = true;
                    btnStartSpd.Enabled = true;
                    btnStopSpd.Enabled = true;
                }
                if (((frmMain)Owner).Settings.CALIBRATION_DONE.CAL_SPEEDO)
                {
                    label4.Text = "Top Speed (Done)";
                    speedTestCompleted = true;
                    btnWrite.Enabled = true;
                }
            }
            if (e.command == Command.PULSES_PER_METER)
            {
                pulsesPerMeter = ((frmMain)Owner).Settings.PULSES_PER_METER;
                lvMperp.Value = ((int)(pulsesPerMeter + 0.5)).ToString();
            }
            if (e.command == Command.MAX_SPEED_PPS)
            {
                topSpeed = ((frmMain)Owner).Settings.MAX_SPEED_PPS;
                lvMpers.Value = (topSpeed / pulsesPerMeter).ToString("F2");
                lblStatus.Text = "Top Speed: " + ((topSpeed / pulsesPerMeter) * 3.6).ToString("F2") + "KPH";
            }
        }


        void frmSpeedCal_NewMsg(object sender, NewMessageEventArgs e)
        {
            if (e.msg.msgType == robotMsg.Type.MOT)
            {
                currentImpulses = (e.msg.count_L + e.msg.count_R) / 2;
                lvImpulses.Value = (currentImpulses - impulseOffset).ToString();
            }
            else if (e.msg.msgType == robotMsg.Type.MOV)
            {
                currentSpeed = (currentSpeed * (filterRatio - 1) + ((e.msg.current_speed_L_motor + e.msg.current_speed_R_motor) / 2)) / filterRatio;
                lvFrequency.Value = ((int)currentSpeed).ToString();
                if (resTestCompleted && currentSpeed > topSpeed)
                {
                    topSpeed = currentSpeed;
                    lblStatus.Text = "Top Speed: " + ((topSpeed / pulsesPerMeter) * 3.6).ToString("F2") + "KPH";
                }
            }
        }

        private void btnStartRes_Click(object sender, EventArgs e)
        {
            impulseOffset = currentImpulses;
            lvImpulses.Value = "0";
        }

        private void btnStopRes_Click(object sender, EventArgs e)
        {
            long distance = currentImpulses - impulseOffset;
            if (numMeters.Value > 0 && distance > 0)
            {
                pulsesPerMeter = (float)distance / (float)numMeters.Value;
                lvMperp.Value = ((int)(pulsesPerMeter + 0.5)).ToString();
                resTestCompleted = true;
                btnStartSpd.Enabled = true;
                btnStopSpd.Enabled = true;
            }
            else if (distance == 0) lvMperp.Value = "None!";
            else if (distance < 0) lvMperp.Value = "Reverse?";
            else if (numMeters.Value == 0) lvMperp.Value = "Infinite?";
            else if (numMeters.Value < 0) lvMperp.Value = "Negative?";
        }

        private void numMeters_ValueChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.courseLength = (float)numMeters.Value;
        }

        private void frmSpeedCal_FormClosing(object sender, FormClosingEventArgs e)
        {
            ((frmMain)Owner).serialControl.sendValue(Command.PWM_POWER, 0);
            ((frmMain)Owner).NewMessage -= newMessage;
            ((frmMain)Owner).Settings.StatusEvent -= statusEvent;
            ((frmMain)Owner).Settings.ParameterArrived -= parameterArrived;
        }

        private void trkPwm_Scroll(object sender, EventArgs e)
        {
            if (speedTestEnabled) ((frmMain)Owner).serialControl.sendValue(Command.PWM_POWER, (int)trkPwm.Value);
        }

        private void btnStartSpd_Click(object sender, EventArgs e)
        {
            speedTestEnabled = true;
            trkPwm.Enabled = true;
            topSpeed = 0;
        }

        private void btnStopSpd_Click(object sender, EventArgs e)
        {
            if (speedTestEnabled) ((frmMain)Owner).serialControl.sendValue(Command.PWM_POWER, 0);
            speedTestEnabled = false;
            trkPwm.Enabled = false;
            lvMpers.Value = (topSpeed / pulsesPerMeter).ToString("F2");
            lblStatus.Text = "Top Speed" + ((topSpeed / pulsesPerMeter) * 3.6).ToString("F2") + "KPH";
            speedTestCompleted = true;
            btnWrite.Enabled = true;
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnWrite_Click(object sender, EventArgs e)
        {
            if (resTestCompleted) {
                ((frmMain)Owner).Settings.PULSES_PER_METER = (int)pulsesPerMeter;
                ((frmMain)Owner).Settings.CALIBRATION_DONE.CAL_ENCODER = true;
            }
            if (speedTestCompleted) {
                ((frmMain)Owner).Settings.MAX_SPEED_PPS = topSpeed;
                ((frmMain)Owner).Settings.CALIBRATION_DONE.CAL_SPEEDO = true;
            }
        }
    }
}
